﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.IdentityModel.JsonWebTokens;
using MyWeb.Common.Helper;
using MyWeb.Model.User;
using MyWeb.Repository.UnitOfWorks;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace MyWeb.Extensions.ServiceExtensions.Filter
{
    /// <summary>
    /// 授权筛选器：用于授权鉴权
    /// </summary>
    public class AuthorizationFilter : IAuthorizationFilter
    {
        public readonly SysUserInfo _sysUser;
        private readonly SqlSugarScope _dbBase;
        public AuthorizationFilter(SysUserInfo sysUserInfo, IUnitOfWorkManage unitOfWorkManage)
        {
            _sysUser = sysUserInfo;
            _dbBase = unitOfWorkManage.GetDbClient();
        }
        public async void OnAuthorization(AuthorizationFilterContext? context)
        {
            //如果是调用的登陆接口不需要做任何验证,就不往下面走了,直接return了
            if (context.Filters.FirstOrDefault(item => item is ILoginUserFilter) is ILoginUserFilter LogintokenFilter)
            {
                return;
            }
            //当调用的接口是加了[AllowAnonymous]特性的,绕过权限验证的
            if (context.ActionDescriptor.EndpointMetadata.Any(item => item is IAllowAnonymous))
            {
                //当调用的接口是加了[FixedToken]特性的都会走这里,FixedToken继承了AllowAnonymous,所以会走IAllowAnonymous
                //(过期token也能访问接口,但必须是最新的那次登陆的token,也就是单设备登陆验证)
                if (context.Filters.Where(item => item is IFixedTokenFilter).FirstOrDefault() is IFixedTokenFilter tokenFilter)
                {
                    //绕过了权限认证的,需要手动去验证token的合法性
                    tokenFilter.OnAuthorization(context);
                    return;
                }
                else
                {
                    //果如只加了[AllowAnonymous]没有加[FixedToken]标签的,就直接绕后任何权限,表示可以直接访问的接口
                    return;
                }
            }

            IMemoryCache? cache = context.HttpContext.RequestServices.GetService(typeof(IMemoryCache)) as IMemoryCache;
            string? token = cache.Get<string>("newjwttoken");
            //用户token错误或者过期,或者token不等于存储的最新的那次token

            string? fixedtoken = string.Empty;
            //if (!context.HttpContext.User.Identity.IsAuthenticated)

            try
            {
                fixedtoken = context.HttpContext.Request.Headers["Authorization"];
                fixedtoken = fixedtoken?.Replace("Bearer ", "");
            }
            catch
            {
                var iden = context.HttpContext.User.Identity;
                if (!(iden is null))
                {
                    fixedtoken = ((ClaimsIdentity)iden)?.BootstrapContext?.ToString();
                }
            }

            bool IsSuccess = true;
            string Message = "";

            if (fixedtoken.IsNullOrEmpty())
            {
                Message = "未授权：Token为空";
                IsSuccess = false;
            }
            DateTime expDate = DateTime.Now;
            if (IsSuccess)
            {
                var aa = JwtHelper.GetJwtSecurityToken(fixedtoken);
                //var bb = JwtHelper.GetSecurityToken(fixedtoken);

                foreach (var claim in aa.Claims)
                {
                    if (claim.Type == ClaimTypes.Expiration)
                    {
                        expDate = claim.Value.ObjToDate();
                    }
                }

                if (expDate <= DateTime.Now)
                {
                    Message = "Token已过期";
                    IsSuccess = false;
                }
            }
            if (IsSuccess && !JwtHelper.customSafeVerify(token: fixedtoken))
            {
                Message = "Token验证无效！";
                IsSuccess = false;
            }

            //(token过期或者不等于最新的那次登陆的token都不能访问接口,与token对比的作用是验证单设备登陆)
            if (IsSuccess && token != fixedtoken)
            {
                Message = "登陆已过期";
                IsSuccess = false;
            }

            if (!IsSuccess)
            {
                context.Result = new JsonResult(new
                {
                    result = "denied",
                    status = false,
                    code = (int)HttpStatusCode.Unauthorized,
                    message = Message
                })
                {
                    ContentType = "application/json",
                    StatusCode = (int)HttpStatusCode.Unauthorized
                };
                return;
            }

            var TokenModel = JwtHelper.SerializeJwt(fixedtoken);

            var user = await _dbBase.Queryable<SysUserInfo>().Where(u => u.Id == TokenModel.Uid).FirstAsync();

            _sysUser.Id = user.Id;
            _sysUser.Name = user.Name;
            _sysUser.LoginName = user.LoginName;
            _sysUser.LoginPWD = user.LoginPWD;
            _sysUser.RealName = user.RealName;


            //就给前端返回一个pms_exp的标识,提醒前端要过期了,让前端重新刷新token,并且呢时候访问的接口不能是调用刷新token的接口
            if ((expDate - DateTime.Now).TotalMinutes < 120 / 12 && context.HttpContext.Request.Path != replaceTokenPath)
            {
                context.HttpContext.Response.Headers.Add("pms_exp", "1");
            }

        }
        //刷新token访问的接口
        private static readonly string replaceTokenPath = "/api/Sys_User/replaceToken";
    }
}
